package GMDPRE

import (
	"fmt"
	"time"
)

const WORDLEN = 8

func testBytesToBN() {
	var mBytes = []uint8{
		0x8, 0xB9, 0x24, 0x35, 0xBF, 0x6F, 0xF7, 0xDD,
		0x29, 0x77, 0x20, 0x63, 0x04, 0x85, 0x62, 0x8D, 0x5A, 0xE7, 0x4E, 0xE7, 0xC3, 0x2E, 0x79, 0xB7}

	var bn BN

	BytesToBn(&bn, WORDLEN, mBytes, len(mBytes))
	for i := WORDLEN - 1; i >= 0; i-- {
		fmt.Printf("%08X", bn[i])

	}
	fmt.Println()
	fmt.Println("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7")
}

func testBNToBytes() {
	var mBytes = []uint8{
		0x8, 0xB9, 0x24, 0x35, 0xBF, 0x6F, 0xF7, 0xDD,
		0x29, 0x77, 0x20, 0x63, 0x04, 0x85, 0x62, 0x8D, 0x5A, 0xE7, 0x4E, 0xE7, 0xC3, 0x2E, 0x79, 0xB7}

	var bn BN

	BytesToBn(&bn, WORDLEN, mBytes, len(mBytes))
	fmt.Printf("Test BnToBytes is correct: %d\n", BytesEqual(BnToBytes(&bn, WORDLEN)[32-len(mBytes):], mBytes, len(mBytes)))
}

func testBnMontMul() {
	var charBufM = "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7"
	var charBufA = "E7933E845253E808990A81E00D2C0443F6F505392A29E6916A53128A5B6E5E9C"
	var charBufB = "5B3472D55740B0938241A245B0F95667DEA6A679C2A41C10E6BFE4F511780CE2"
	var charBufS = "7150FC3BC4E380963B59A304957119F4D6D573EE4893FD44CB5C38D32D943606"

	var byteRRm = []byte{0x62, 0x3C, 0xD3, 0x3A, 0xF6, 0x48, 0xF5, 0x7F, 0xBC, 0xC0, 0x0B, 0xDB, 0xE3, 0xD0, 0xDC, 0xC3,
		0xD5, 0x45, 0xF5, 0x2A, 0x3A, 0xDC, 0x0B, 0x84, 0xCE, 0x21, 0x2B, 0x94, 0x11, 0x27, 0xD0, 0x53}
	var byteBuf []byte
	var bnM BN
	var bnRRm BN
	var bnA BN
	var bnB BN
	var bnC BN
	var bnD BN

	var mc DigT = 0x62F54BF9
	BytesToBn(&bnRRm, WORDLEN, byteRRm, len(byteRRm))

	byteBuf = HexToBytes(charBufM)
	BytesToBn(&bnM, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufA)
	BytesToBn(&bnA, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufB)
	BytesToBn(&bnB, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufS)
	BytesToBn(&bnD, WORDLEN, byteBuf, len(byteBuf))

	BnMontMul(&bnA, &bnA, &bnRRm, &bnM, mc, Sm2CurveDigit)
	BnMontMul(&bnB, &bnB, &bnRRm, &bnM, mc, Sm2CurveDigit)
	BnMontMul(&bnC, &bnA, &bnB, &bnM, mc, Sm2CurveDigit)
	BnMontRdc(&bnC, &bnC, &bnM, mc, Sm2CurveDigit)

	fmt.Printf("Test BnMontMul is correct: %d\n", BnEqual(&bnC, &bnD, WORDLEN))
}

func testBnMontMulV2() {
	var charBufM = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
	var charBufA = "fe86f9989aade724fd9e7bd084798c75e21b5151e393294bb7f6e1ad03271f56"
	var charBufB = "38d17fb019dca7ce08fa7422acf89a0ed84e472156a5e04bad920a86586b8911"
	var charBufS = "2672f7a85c410283716a3c03438008293ce52c540183e3d078d96d944664cbf7"

	var byteBuf []byte
	var bnM BN
	var bnRRm BN
	var bnA BN
	var bnB BN
	var bnC BN
	var bnD BN

	var mc DigT

	byteBuf = HexToBytes(charBufM)
	BytesToBn(&bnM, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufA)
	BytesToBn(&bnA, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufB)
	BytesToBn(&bnB, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufS)
	BytesToBn(&bnD, WORDLEN, byteBuf, len(byteBuf))

	BnMontInit(&mc, &bnM)
	BnInitMontRRm(&bnRRm, &bnM, Sm2CurveDigit)

	BnMontMul(&bnA, &bnA, &bnRRm, &bnM, mc, Sm2CurveDigit)
	BnMontMul(&bnB, &bnB, &bnRRm, &bnM, mc, Sm2CurveDigit)
	BnMontMul(&bnC, &bnA, &bnB, &bnM, mc, Sm2CurveDigit)
	BnMontRdc(&bnC, &bnC, &bnM, mc, Sm2CurveDigit)

	fmt.Printf("Test BnMontMulV2 is correct: %d\n", BnEqual(&bnC, &bnD, WORDLEN))
}

func testBnMontExp() {
	var charBufM = "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7"
	var charBufA = "E7933E845253E808990A81E00D2C0443F6F505392A29E6916A53128A5B6E5E9C"
	var charBufE = "20268CCD1BA7CD9B4AC3CD107DD0417ECD964936A3B0B50A65EBA12A0BD66A85"
	//var charBufE = "942abfe5ad454936147945312973124554a11d54525479554da364215526969d"
	var charBufS = "C76CD59CAA8AE970B279C2C3C4F317168C5126AE4A23F0E51A6D6285370471D"
	//var charBufS = "1875aa4e68352944af93f4f40e794e8a6d09269ebac449176fe7a1de70c2f59"

	var byteRRm = []byte{0x62, 0x3C, 0xD3, 0x3A, 0xF6, 0x48, 0xF5, 0x7F, 0xBC, 0xC0, 0x0B, 0xDB, 0xE3, 0xD0, 0xDC, 0xC3,
		0xD5, 0x45, 0xF5, 0x2A, 0x3A, 0xDC, 0x0B, 0x84, 0xCE, 0x21, 0x2B, 0x94, 0x11, 0x27, 0xD0, 0x53}
	var byteBuf []byte
	var bnM BN
	var bnRRm BN
	var bnA BN
	var bnE BN
	var bnC BN
	var bnD BN

	var mc DigT = 0x62F54BF9
	BytesToBn(&bnRRm, WORDLEN, byteRRm, len(byteRRm))

	byteBuf = HexToBytes(charBufM)
	BytesToBn(&bnM, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufA)
	BytesToBn(&bnA, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufE)
	BytesToBn(&bnE, WORDLEN, byteBuf, len(byteBuf))

	byteBuf = HexToBytes(charBufS)
	BytesToBn(&bnD, WORDLEN, byteBuf, len(byteBuf))

	BnMontMul(&bnA, &bnA, &bnRRm, &bnM, mc, Sm2CurveDigit)
	BnMontExp(&bnC, &bnA, &bnE, &bnM, mc, Sm2CurveDigit)
	BnMontRdc(&bnC, &bnC, &bnM, mc, Sm2CurveDigit)

	fmt.Printf("Test BnMontExp is correct: %d\n", BnEqual(&bnC, &bnD, WORDLEN))
}

func TestBn() {
	fmt.Println("+------------------------------------------------------------------------------+")
	fmt.Println("+---    Test module  --->  bn")

	//testBytesToBN()
	testBNToBytes()
	testBnMontMul()
	testBnMontMulV2()
	testBnMontExp()

	fmt.Println("+------------------------------------------------------------------------------+")
}

func benchBnMontMul() {
	var x1, x2, y BN
	var cost int64 = 0
	var start time.Time

	var i, j int
	for i = 0; i < 100; i++ {
		BytesToBn(&x1, WORDLEN, GetRandomBytes(Sm2CurveSize), Sm2CurveSize)
		BytesToBn(&x2, WORDLEN, GetRandomBytes(Sm2CurveSize), Sm2CurveSize)

		start = time.Now()
		for j = 0; j < 10; j++ {
			BnMontMul(&y, &x1, &x2, &Sm2Q, Sm2McQ, Sm2CurveDigit)
		}
		// 单位：微秒
		cost += time.Since(start).Microseconds()

	}

	fmt.Printf("bench BnMontMul: %.3f us\n", float64(cost)/1000.0)
}

func BenchBn() {
	fmt.Println("+------------------------------------------------------------------------------+")
	fmt.Println("+---    Bench module  --->  bn")
	benchBnMontMul()
	fmt.Println("+------------------------------------------------------------------------------+")
}
